package com.starview.star.operators.relation.runtime;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IConstructor;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IRelation;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.Refresher;
import com.starview.platform.data.type.StandardTypes;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.type.TypeVar;
import com.starview.star.compiler.standard.StandardNames;
import com.starview.star.operators.CafeEnter;

public class RelationIterable
{
  public static class RelationIterate implements IFunction
  {
    public static final String name = "__relation_iterate";

    @CafeEnter
    public static IValue enter(IValue data, IFunction iter, IValue state) throws EvaluationException
    {
      IRelation relation = (IRelation) data;

      if (!(state instanceof IConstructor && ((IConstructor) state).getLabel().equals(StandardNames.NOMORE)))
        for (IValue el : relation) {
          state = iter.enter(el, state);
          if (state instanceof IConstructor && ((IConstructor) state).getLabel().equals(StandardNames.NOMORE))
            break;
        }
      return state;
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return enter(args[0], (IFunction) args[1], args[2]);
    }

    @Override
    public IType getType()
    {
      return RelationIterate.type();
    }

    public static IType type()
    {
      // %e~%s~(relation of %e,(%e,%s)=>%s,%s) => %s

      TypeVar e = new TypeVar();
      TypeVar s = new TypeVar();

      IType relType = TypeUtils.typeExp(StandardTypes.RELATION, e);

      IType funType = TypeUtils.functionType(relType, TypeUtils.functionType(e, s, s), s, s);
      return Refresher.generalize(funType);
    }
  }
}
